--
-- Author: shunguo.chen
-- Date: 2016-06-20 12:38:27
--

local IMMessage = import(".IMMessage")

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ModelBase)

local CHANNEL_NAMES = {
	all = L("lua_code_text_354"),
	system = L("text_11400006"),
	map = L("text_11400007"),
	world = L("text_11400008"),
	team = L("text_11400009"),
	guild = L("text_11400010"),
	p2p = L("text_11400011"),
	teamreq = L("text_11400012")
}
local CHANNEL_S_NAMES = {
	system = L("lua_code_text_62"),
	map = L("lua_code_text_233"),
	world = L("lua_code_text_520"),
	team = L("lua_code_text_435"),
	guild = L("lua_code_text_235"),
	p2p = L("lua_code_text_394"),
	teamreq = L("lua_code_text_416")
}
local CHANNEL_IDS = {"all", "world", "team", "guild", "map", "p2p", "teamreq", "system"}
local CHANNEL_ROOM_IDS = {"world", "team", "guild", "system", "p2p", "teamreq"}

local MESSAGE_All_MAX_NUM = 200
local MESSAGE_MAX_NUM = 100
local MESSAGE_P2P_MAX_NUM = 20

--剩余消息一次提取数量
local GET_REST_MSG_PER_NUM = 10
local MESSAGE_RENDER_MAX_NUM = 20
local TARGET_MAX_NUM = 6
local TARGET_EMPTY = {name=L("text_10601009"), color="#FFFFFF"}

local IM_CONF = nil
local GM_DISABLE = app.configuration:getValue("GM_DISABLE") or false

local CHANNEL_WORLD_GAP = tonumber(GD:getSystemPar("channelworldgap",2))
local featureConf = GD:queryFeatureOnById(92) or {}
local CHANNEL_WORLD_OPEN_LEVEL = tonumber(featureConf.level or 5)

local CHANNEL_TEAMREQ_GAP = tonumber(GD:getSystemPar("channelrecruitgap", 5))

-- settingidx=====channelId
local SETTINGIDX_CHANNELID = {"world", "teamreq", "team", "guild", "p2p", "system"}

function ClassRef:ctor(data)
	self.super.ctor(self, data)
end

function ClassRef:init()
	self._isLogin = false
	self._chatRoomDict = nil

	self._allMsgList = {}
	self._msgDict = {}

	self._myMsgDict = {}
	self._teamMsgList = {}

	self._targetList = {}
	self._targetCache = {}

	-- audio file cache
	self._audioFileCache = {}

	--各个频道未显示的消息数量
	self._restMsgNums = {0,0,0,0,0,0,0,0}

	-- 拉取附件时保存用来拉取成功之后获取msg
	self._downloadAudioDict = {}
	self._uploadAudioDict = {}

	self._teamTarget = nil

	self._emojiDatas = nil
	self._equipDatas = nil
	self._mountDatas = nil
	self._jewelDatas = nil
	self._itemDatas = nil

	self._wordSendTime = 0
    self._teamreqSendTime = 0

	-- voice mode
	self._mode = im.Mode.Translate

	self._curChannelIdx = 1 -- 当前选择频道
	self._curP2PTarget = nil -- 当前选择密聊的目标
	self._newP2PMessageList = {} -- 密聊小红点

	self:_initChatroom()
end


function ClassRef:_initChatroom()
	if not self._chatRoomDict then
		IM_CONF = app:loadResScript("scripts.config.IMConfig")

		self._chatRoomDict = {}

		for i,v in ipairs(CHANNEL_ROOM_IDS) do
			local room = {}
			room.roomId = v
			room.name = CHANNEL_NAMES[v]
			room.sname = CHANNEL_S_NAMES[v]
			room.color = IM_CONF.channelColor[v]
			if v == "world" or v == "system" then
				room.uid = v
			else
				room.uid = nil
			end
			if v == "team" then
				room.sessionType = im.SessionType.Team
			elseif v == "p2p" then
				room.sessionType = im.SessionType.P2p
			else
				room.sessionType = im.SessionType.Chatroom
			end
			self._chatRoomDict[v] = room
		end
	end
end

function ClassRef:getRecordPath()
	return app:getTempFolder() .. "/gvoice_" .. math.ceil(app:getTime()) .. ".dat"
end

function ClassRef:updateItem(uid,item,amountGot)
	-- print("IMModel:updateItem() amountGot = " .. tostring(amountGot))
	if not item then return end
	local name
	if item.itemBagType == Enums.ItemBagType.equip then
		if item.isNew then
			self._equipDatas = nil
			name = item:getName(true)
		end
	elseif item.itemBagType == Enums.ItemBagType.item then
		self._itemDatas = nil
		name = item:getName(true)
	elseif item.itemBagType == Enums.ItemBagType.jewel then
		self._jewelDatas = nil
		name = item:getName(true)
	end
	if name and amountGot > 0 then
		self:addSystemMsg("gotitem", {amountGot, name})
	end
end
function ClassRef:updateEquip()
	-- print("IMModel:updateEquip()")
	self._equipDatas = nil
end
function ClassRef:updateMount()
	-- print("IMModel:updateMount()")
	self._mountDatas = nil
end

function ClassRef:updateFame(uid, fame)
	-- dump(fame, "IMModel:updateFame() fame ")
	if fame then
		local conf = GD:queryFameById(uid) or {}
		local name = L(conf.name, uid)
		local fameAdd = fame:getFameAdd()
		if fameAdd > 0 then
			self:addSystemMsg("gotfame", {name, fameAdd})
		end
		if fame.level > fame.preLev then
			local levConf = GD:queryFameLevelUpById(fame.level)
			local level = levConf and L(levConf.name) or fame.level
			self:addSystemMsg("famelevelup", {name, level})
		end
	end
end
function ClassRef:updateAchievement(uid, achieve)
	if achieve and achieve:isComp() then
		local conf = GD:getAchievementConfig(uid)

		-- 1.没有配置 2.配置showtype＝1 不添加log
		if not conf then return end
		if conf.showType == "1" then return end

		local name = conf.name or uid
		self:addSystemMsg("gotachievement", {L(name)})

		-- 聊天功能可用，需要主动向队伍和工会频道发送获得成就消息
		if not im.isValid() then return end

		local text = table.concat({"tips_1090005", UD.player.name, name}, ",")
		text = "[s|" .. text .. "]"

		self:sendTeamMessage(text)
		self:sendGuildMessage(text)
	end
end
function ClassRef:updatePlayer(name, old, new)
	-- printf("IMModel:updatePLayer name=%s, old=%s, new=%s", name, old, new)
	if name == "level" then
		self:addSystemMsg("levelup", {new})
		if old < CHANNEL_WORLD_OPEN_LEVEL and new >= CHANNEL_WORLD_OPEN_LEVEL then
			app:sendMsg("IMRoomController", "updateWorldOpen")
			app:sendMsg("IMSimpleController", "updateWorld", true)
		end
	elseif name == "coin" then
		if new > old then
			self:addSystemMsg("gotgem", {new-old})
		else
			self:addSystemMsg("usegem", {old-new})
		end
	end
end
function ClassRef:updateAnnounce(msg)
	if not msg.content and msg.msgID then
        local messageStr = L(msg.msgID)
        if msg.values then
	        local r,r1,r2 = pcall(string.format, messageStr, unpack(msg.values))
	        if r then
	            msg.content = string.format(messageStr, unpack(msg.values))
	        end
	    else
	    	msg.content = L(msg.msgID)
	    end
    end
    -- print("IMModel:updateAnnounce", tostring(msg.content))
    if msg.content then
		self:addSystemMsg(msg.content)
	end
end

function ClassRef:updateTeam(team)
	local uid = team and team:getTeamId() or nil
	-- print("IMModel:updateTeam uid = " .. tostring(uid))
	local room = self._chatRoomDict["team"]
	if uid ~= room.uid then
		room.uid = uid
		app:sendMsg("IMRoomController", "teamChanged")
		app:sendMsg("IMRecordController", "updateTeam", uid)
		app:sendMsg("IMSimpleController", "updateTeam", uid~=nil)
	end
end

function ClassRef:updateGuild(uid)
	if uid == {} then uid = nil end
	-- print("IMModel:updateGuild uid = " .. tostring(uid))
	local room = self._chatRoomDict["guild"]
	if uid ~= room.uid then
		room.uid = uid
		app:sendMsg("IMRoomController", "guildChanged")
		app:sendMsg("IMSimpleController", "updateGuild", uid~=nil)
	end
end

-- 重连成功，服务器会下发最新聊天记录，本地缓存需要清除
function ClassRef:onReconnectSuccessed()
	self._allMsgList = {}
	self._msgDict = {}
	self._myMsgDict = {}
	self._teamMsgList = {}
end

function ClassRef:isWorldOpen()
	return UD.player.level >= CHANNEL_WORLD_OPEN_LEVEL, CHANNEL_WORLD_OPEN_LEVEL
end
function ClassRef:isInTeam()
	return self._chatRoomDict["team"].uid ~= nil
end
function ClassRef:isInGuild()
	return self._chatRoomDict["guild"].uid ~= nil
end

--params:
--message IMMessage
-- 注意：按时间顺序逆序排列，时间越大越靠后
function ClassRef:addMessageCache(message)
	-- dump(msg, "IMModel:addMessageCache()")

	local function insertMsg(tab, msg, max, show)
		if tab == nil then
			return
		end

		max = max or MESSAGE_MAX_NUM
		if #tab == max then
			table.remove(tab, 1)
			local channelIdx = table.indexof(CHANNEL_IDS, msg.channelId)
			self._restMsgNums[channelIdx] = math.max(self._restMsgNums[channelIdx] - 1, 0)
		end
		if show ~= nil then
			msg.showFlag = show -- 这个字段只在综合频道有效，判断此条消息是否显示在综合频道
		else
			msg.showFlag = true
		end
		tab[#tab + 1] = msg
	end

	if message.sessionType == im.SessionType.Chatroom then
		local roomId = message.channelId
		self._msgDict[roomId] = self._msgDict[roomId] or {}
		insertMsg(self._msgDict[roomId], message)
	elseif message.sessionType == im.SessionType.P2p then
		local key = message:getTarget()
		self._myMsgDict[key] = self._myMsgDict[key] or {}
		insertMsg(self._myMsgDict[key], message, MESSAGE_P2P_MAX_NUM)

		-- 私聊要在世界里面出现
		--self._msgDict["world"] = self._msgDict["world"] or {}
		--insertMsg(self._msgDict["world"], message)
	elseif message.sessionType == im.SessionType.Team then
        --local hasTeam = app:getInst("TeamModel"):hasTeam()
        --if (hasTeam and message:isTeamMsg()) or (not hasTeam and message:isTeamreqMsg()) then
		    insertMsg(self._teamMsgList, message)
        --end
	end

	-- if message.sessionType ~= im.SessionType.P2p and not message:isTeamreqMsg() then
	--if not message:isTeamreqMsg() then
	local index = self:getSettingIdxByChannelName(message.channelId)
	local showFlag = UD.setting:getImChannelInfoSet(index)
	insertMsg(self._allMsgList, message, MESSAGE_All_MAX_NUM, showFlag)
	--end
end

function ClassRef:addAudioFileCache(fileId, filePath)
	self._audioFileCache[fileId] = filePath
end
function ClassRef:removeAudioFileCache(fileId)
	self._audioFileCache[fileId] = nil
end

function ClassRef:onSpeakInChatroom(message)
	if message:isAudioMsg() and message.text == "" then return end
	local showBubble = false
	if message.channelId == "world" then
		showBubble = UD.setting:isShowWorldBubble()
	elseif message.channelId == "team" then
		showBubble = UD.setting:isShowTeamBubble()
	elseif message.channelId == "guild" then
		showBubble = UD.setting:isShowGuildBubble()
	elseif message.channelId == "teamreq" then
		showBubble = UD.setting:isShowTeamreqBubble()
	elseif message.channelId == "system" then
		-- TEST
		-- showBubble = DEBUG > 0
	end
	if showBubble then
		-- dump(message, "IMmodel.onSpeakInChatroom()")
		self:notify("onSpeakInChatroom", message)
	end
end

-- msgs = {S2C_InterChat,...}
-- message S2C_InterChat {
-- 	ChatType chat_type = 1;
-- 	Avatar fromUser = 2;
-- 	string msg = 3;
-- 	int64 toUID = 4;
-- 	int64 timeStamp = 5;
-- 	bool CachedMsg = 6;
-- 	string params = 7;//特殊数据
-- }
function ClassRef:onRecvMessages(msgs)
	-- dump(msgs, "IMModel.onRecvMessages", 10)
	if not self._isLogin then return end
	
	local messages = {}
	for _,msg in ipairs(msgs) do
		if msg.chat_type == "none" then
			-- gm密令返回
			local message = IMMessage.new()
			local room = self._chatRoomDict["system"]
			message:initWithGM(msg, room)
			messages[#messages + 1] = message
		else
			local uid = msg.fromUser.uid
			local isMe = UD:isMe(uid)

			-- 只处理 1. 自己发出的消息 2. 非黑名单发出的消息
			if isMe or not UD:isBlack(uid) then
				-- 如果是跨服频道，需要转到team存储
				local chat_type = msg.chat_type
				if chat_type == "crossDungeon" then
					chat_type = "team"
				end

				local message = IMMessage.new()
				local room = self._chatRoomDict[chat_type]
				message:init(msg, room)

				if message:isAudioMsg() and message.isOutgoingMsg then
					local path = self._audioFileCache[message.fileId]
					if path then
						self:removeAudioFileCache(message.fileId)
						message:setDownloadState(im.MessageAttachState.Downloaded)
						message:setAudioPath(path)
					end
				end

				-- 私聊 添加对象缓存
				if message.sessionType == im.SessionType.P2p then
					if message.isOutgoingMsg then
						local info = self._targetCache[msg.toUID]
						message:setTargetInfo(info)
						self:addTargetList(info)
						self:addNewP2PMessage(info.uid)
					else
						self:addTargetList(message:getSenderInfo())
						self:addNewP2PMessage(message:getSenderInfo().uid)
					end
				end

				self:addMessageCache(message)

				if message:needFetchAttach() then
					-- local auto = UD.setting:isAutoAudio2Text()
					local auto = false
					if not auto then
						if message.channelId == "world" then
							auto = UD.setting:isAutoPlayAudioWorld()
						elseif message.channelId == "guild" then
							auto = UD.setting:isAutoPlayAudioGuild()
						elseif message.channelId == "team" then
							auto = UD.setting:isAutoPlayAudioTeam()
						elseif message.channelId == "teamreq" then
							-- 组队语音会自动下载
							auto = true
						end
					end
					local hasMicOrSpeaker = app:sendMsg("IMRecordController", "hasMicOrSpeaker")
					if auto and not hasMicOrSpeaker then
						self:fetchAttach(message)
					end
				end

				messages[#messages + 1] = message
			end
		end
	end

	-- 进入游戏才发出消息
	if #messages > 0 then
		self:dispatchNewMessage(messages)
	end
end

function ClassRef:dispatchNewMessage(msgs)
	scheduler.performWithDelayGlobal(function()
			for _,msg in ipairs(msgs) do
				if not msg.isCache then
					self:onSpeakInChatroom(msg)
				end
			end
			self:notify("im_newMessages", msgs)
		end, 0)
end

function ClassRef:dispatchMessageUpdate(message)
	app:sendMsg("IMRoomController", "updateMessage", message)
	app:sendMsg("IMSimpleController", "updateMessage", message)
end

-- params
-- key(string)  	string表id／输出字符串
-- params(table/string/number) 	填充输出匹配符的数据
-- ignoreTag(bool) 	是否忽略消息前面的文字"［系统］"
function ClassRef:addSystemMsg(key, params, ignoreTag)
	-- print("IMModel:addSystemMsg key = ", key)
	if not self._isLogin then return end
	if nil == self._chatRoomDict["system"] then return end
	ignoreTag = ignoreTag or false
	local text = L(key)
	if params then
		if type(params) == "table" then
			-- dump(params, "IMModel:addSystemMsg params")
			text = string.format(text, unpack(params))
		else
			-- print("IMModel:addSystemMsg params", params)
			text = string.format(text, params)
		end
	end

	-- print("IMModel:addSystemMsg text = " .. text)

	local message = IMMessage.new()
	local room = self._chatRoomDict["system"]
	message:initWithSystem(text, room, ignoreTag)
	self:addMessageCache(message)
	self:onSpeakInChatroom(message)
	self:notify("im_newMessages", {message})
end

-- 同addSystemMsg
function ClassRef:addGuildMsg(key, params, ignoreTag)
	if not self:isInGuild() then return end
	-- print("IMModel:addGuildMsg key = ", key)
	if nil == self._chatRoomDict["system"] then return end
	ignoreTag = ignoreTag or false
	local text = L(key)
	if params then
		if type(params) == "table" then
			-- dump(params, "IMModel:addGuildMsg params")
			text = string.format(text, unpack(params))
		else
			-- print("IMModel:addGuildMsg params", params)
			text = string.format(text, params)
		end
	end

	-- print("IMModel:addGuildMsg text = " .. text)

	local message = IMMessage.new()
	local room = self._chatRoomDict["guild"]
	message:initWithSystem(text, room, ignoreTag)
	self:addMessageCache(message)
	self:onSpeakInChatroom(message)
	self:notify("im_newMessages", {message})
end

-----------------------------------------------------------------------
-- playerInfo = {name=, uid=, sessionType=, ...}
function ClassRef:addTargetList(info)
	-- dump(info, "IMModel.addTargetList")
	if nil == info or nil == info.uid then return end
	self._targetCache[info.uid] = info
	-- dump(self._targetCache, "IMModel._targetCache")
	local idx = nil
	for i=1, #self._targetList do
		if self._targetList[i].uid == info.uid then
			idx = i
			break
		end
	end

	if idx then
		if idx ~= 1 then
			table.remove(self._targetList, idx)
			table.insert(self._targetList, 1, info)
		end
	else
		table.insert(self._targetList, 1, info)
	end
end

function ClassRef:getTargetList(channelIdx)
	local ret = {}
	if channelIdx == 1 then

	elseif channelIdx == 2 then
		ret[1] = self._chatRoomDict["world"]
	elseif channelIdx == 3 then
		ret[1] = self._chatRoomDict["team"]
	elseif channelIdx == 4 then
		ret[1] = self._chatRoomDict["guild"]
	elseif channelIdx == 5 then

	elseif channelIdx == 6 then
		ret = self._targetList
	elseif channelIdx == 7 then

	elseif channelIdx == 8 then
		if not GM_DISABLE then
			ret[1] = self._chatRoomDict["system"]
		end
	end
	return ret
end

function ClassRef:getChannelName(channelIdx)
	local id
	if channelIdx == 1 then
		id = "all"
	elseif channelIdx == 2 then
		id = "world"
	elseif channelIdx == 3 then
		id = "team"
	elseif channelIdx == 4 then
		id = "guild"
	elseif channelIdx == 5 then
		id = "map"
	elseif channelIdx == 6 then
		id = "p2p"
	elseif channelIdx == 7 then
		id = "teamreq"
	elseif channelIdx == 8 then
		id = "system"
	end
	return string.format( L("lua_code_text_432"), CHANNEL_NAMES[id] ) 
end

function ClassRef:getChannelIdxById(channelId)
	local idx
	if channelId == "world" then
		idx = 2
	elseif channelId == "team" then
		idx = 3
	elseif channelId == "guild" then
		idx = 4
	end
	return idx
end

function ClassRef:getChannelTarget(id)
	return self._chatRoomDict[id]
end

-- channelIdx = 1 综合
-- channelIdx = 2 世界
-- channelIdx = 3 队伍
-- channelIdx = 4 工会
-- channelIdx = 5 附近(当前地图)
-- channelIdx = 6 蜜语
-- channelIdx = 7 组队?(search)
-- channelIdx = 8 系统
function ClassRef:getChannelData(channelIdx, isAll, uid)
	isAll = isAll or false
	local ret
	if channelIdx == 1 then
		-- TEST 全部聊天记录s
		ret = self._allMsgList
	elseif channelIdx == 2 then
		ret = self._msgDict["world"]
	elseif channelIdx == 3 then
		ret = self._teamMsgList
	elseif channelIdx == 4 then
		ret = self._msgDict["guild"]
	elseif channelIdx == 5 then
		-- ret = self._msgDict["map"]
	elseif channelIdx == 6 then
		ret = self:getP2pChannelData(uid)
	elseif channelIdx == 7 then
		ret = self._msgDict["teamreq"]
	elseif channelIdx == 8 then
		ret = self._msgDict["system"]
	end

	ret = ret or {}
	if not isAll then
		if #ret > MESSAGE_RENDER_MAX_NUM then
			local resNum = #ret - MESSAGE_RENDER_MAX_NUM
			self._restMsgNums[channelIdx] = resNum
			-- print("resNum", resNum)
			-- print("#ret", #ret)
			return table.sub(ret, resNum+1, #ret)
		else
			self._restMsgNums[channelIdx] = 0
			return ret
		end
	else
		return ret
	end
end

function ClassRef:getRestChannelData(channelIdx)
	-- 私聊都一次性显示
	if channelIdx == 6 then return end
	local num = self._restMsgNums[channelIdx]
	local ret
	if num > 0 then
		local msgs = self:getChannelData(channelIdx, true)
		local endIdx = num
		local startIdx = num > GET_REST_MSG_PER_NUM and (num - GET_REST_MSG_PER_NUM + 1) or 1

		ret = {}
		for i=endIdx, startIdx, -1 do
			ret[#ret + 1] = msgs[i]
		end
		self._restMsgNums[channelIdx] = startIdx - 1
	end
	return ret
end

function ClassRef:getP2pChannelData(uid)
	if not uid then
		local target = self._targetList[1]
		uid = target and target.uid or nil
	end
	if uid then
		return self._myMsgDict[uid] or {}
	else
		return {}
	end
end

---------------------------------- request ----------------------------------
function ClassRef:voiceLogin()
	if im.isValid() and not im.isVoiceInit then
		local openId = app.channelAPI:getOpenId()
		local appId = app.configuration:getValue("GVOICE_APPID") or "886719905"
		local appKey = app.configuration:getValue("GVOICE_APPKEY") or "1d47b48472c18cde3db5fa7ccbba49ae"
	    local code = im.initVoice(appId, appKey, openId)
		-- print("im.initVoice code", code)
		im.isVoiceInit = (code == 0)
	    if code == 0 then
	    	self:applyMessageKey()
	    end
	end
end

function ClassRef:login()
	-- print("IMModel.login")
	self._isLogin = true
	self:voiceLogin()
end

function ClassRef:logout()
	-- print("IMModel.logout")
	self._isLogin = false

	im.isVoiceInit = false
	im.isGotApplyKey = false
	im.isPlaying = false

	-- quit room
	app:sendMsg("IMRecordController", "updateTeam")
end

-- 设置gvoice的mode
function ClassRef:setMode(mode)
	if self._mode ~= mode then
		local code = im.setMode(mode)
		if code == 0 then
			self._mode = mode
			-- print("IMModel.mode", mode)
		end
		return code == 0
	else
		return true
	end
end
function ClassRef:setModeTranslate()
	self:setMode(im.Mode.Translate)
end
function ClassRef:setModeRealTime()
	self:setMode(im.Mode.RealTime)
end
function ClassRef:isModeTranslate()
	return self._mode == im.Mode.Translate
end
function ClassRef:isModeRealTime()
	return self._mode == im.Mode.RealTime
end

function ClassRef:applyMessageKey()
	if not im.isGotApplyKey then
		local code = im.applyMessageKey()
		-- print("im.applyMessageKey code", code)
	end
end

-- 发送系统消息，正常会被屏蔽，主要用来发GM密令
function ClassRef:sendSystemMessage(text)
	local room = self._chatRoomDict["system"]
	local params = {}
	params.messageType = im.MessageType.Text
	params.text = text
	params.uid = room.uid
	params.sessionType = room.sessionType
	params.roomId = "system"
	self:sendMessage(params)
end

-- 发送消息到队伍频道
function ClassRef:sendTeamMessage(text)
	if self:isInTeam() then
		local room = self._chatRoomDict["team"]
		local params = {}
		params.messageType = im.MessageType.Text
		params.text = text
		params.uid = room.uid
		params.sessionType = room.sessionType
		params.roomId = "team"
		self:sendMessage(params)
	end
end

-- 发送消息到工会频道
function ClassRef:sendGuildMessage(text)
	if self:isInGuild() then
		local room = self._chatRoomDict["guild"]
		local params = {}
		params.messageType = im.MessageType.Text
		params.text = text
		params.uid = room.uid
		params.sessionType = room.sessionType
		params.roomId = "guild"
		self:sendMessage(params)
	end
end

-- params = {
-- 	   messageType=,
-- 	   text=,
-- 	   uid=,
-- 	   sessionType=,
-- 	   roomId=, -- p2p没有，需要额外填充
-- }
function ClassRef:sendMessage(params)
	-- p2p 没有填充 roomId
	params.roomId = params.roomId or "p2p"

	-- dump(params, "IMModel:sendMessage() params")

	if params.sessionType == im.SessionType.Chatroom then
		local room = self._chatRoomDict[params.roomId]
		if room then
			if room.roomId == "world" then
				local restTime = CHANNEL_WORLD_GAP - (app:getTime() - self._wordSendTime)
				if restTime > 0 then
					display.pushToast(string.format(L("tips_2000219"), math.ceil(restTime)))
					return params.messageType ~= im.MessageType.Text
				else
					self:IMSendMessage(params)
				end
            elseif room.roomId == "teamreq" then
                local restTime = CHANNEL_TEAMREQ_GAP - (app:getTime() - self._teamreqSendTime)
                if restTime > 0 then
                    --display.pushToast(string.format(L("tips_2000219"), math.ceil(restTime)))
					return params.messageType ~= im.MessageType.Text
                else
                    self:IMSendMessage(params)
                end
			else
				self:IMSendMessage(params)
			end
		else
			return params.messageType ~= im.MessageType.Text
		end
	elseif params.sessionType == im.SessionType.P2p then
		self:IMSendMessage(params)
	else
		self:IMSendMessage(params)
	end

	return true
end

ClassRef._preParams = nil
-- message C2S_InterChat {
--  ChatType chat_type = 1; // channel type
-- 	int64 toUID = 2;
-- 	string msg = 3; //  chat message
-- 	string params = 4; //  特殊数据
-- }
function ClassRef:IMSendMessage(params)
	local function sendFinalMsg()
		local param = {}
		param.chat_type = params.roomId
		-- 如果是队伍，并且是跨服副本，需要转到跨服频道
		if params.roomId == "team" and DungeonManager:isCrossDungeon() then
			param.chat_type = "crossDungeon"
		end
		if params.roomId == "p2p" then
			param.toUID = params.uid
		elseif params.roomId == "world" then
			self._wordSendTime = app:getTime()
        elseif params.roomId == "teamreq" then
            self._teamreqSendTime = app:getTime()
		end

		local replaceAry = {}
		param.msg = string.gsub(params.text, "(%[[emtiqjcarsuvhzogd]|[^%[%]]+%])", 
			function(v)
				replaceAry[#replaceAry + 1] = v
				return "{" .. #replaceAry .. "}"
			end)

		param.params = table.concat(replaceAry, "##")

		-- dump(param, "IMSendMessage.param")
		app.session:request("pb_chat.C2S_InterChat", param)
	end

	if app:isNeedCheckInput() and params.roomId ~= "system" then
		app:checkInput(params.text, function(response,errorMsg,code)
			if code == 200 then
				if response and response.result then
					params.text = response.result
					sendFinalMsg()
				end
			else
				display.pushToast(L("network_error"))
			end
		end, true)
	else
		sendFinalMsg()
	end
end

function ClassRef:queryUserDetail(param)
	-- dump(param, "IMModel:queryUserDetail param")
	app.session:request("pb_query.C2S_QueryUserDetail", param, function(ret)
		-- dump(ret, "IMModel queryUserDetail ret")
		if ret.ok then
			app:sendMsg("IMRoomController", "showTip", ret.result, param)
		else
			display.pushToast(L("tips_1150007"))
		end
	end)
end

---------------- record audio ----------------
function ClassRef:onRecordSucc(channel, filePath, duration)
	-- print("===>IMAPI onRecordSucc")
	if channel ~= "current" then
		local target = self:getChannelTarget(channel)
		if target then
			self:msgUploadAudio(filePath, duration, target)
		else
			-- print("===>IMAPI IMRoomController.onRecordSucc error channel", channel)
			app:sendMsg("IMRecordController", "needBackToRealtime")
		end
	else
		self:msgUploadAudio(filePath, duration)
	end
end

function ClassRef:onUploadEnd(succ, filePath, fileId)
	-- print("===>IMAPI onUploadEnd succ", succ)

	local temp = self._uploadAudioDict[filePath]
	self._uploadAudioDict[filePath] = nil
	local tempType = type(temp)
	if tempType == "table" then
		-- 聊天语言消息
		if succ then
			self._audioParam.fileId = fileId
			self:addAudioFileCache(fileId, filePath)

			self:audio2Text(fileId)
		else
			self._audioParam = nil
			app:sendMsg("IMRecordController", "needBackToRealtime")
		end
	elseif tempType == "function" then
		-- 组队语言
		if succ then
			executeFunc(temp, filePath, fileId)
		else
			executeFunc(temp)
		end
	end
end

-- 上传audio，一种是带cb（非聊天消息上传），一种不带cb（聊天消息上传）
-- 数据都存在 slef._uploadAudioDict里面
function ClassRef:uploadAudio(filePath, cb)
	if cb then
		self._uploadAudioDict[filePath] = cb
	end

	self:setModeTranslate()
	local code = im.uploadAudio(filePath)
	if code ~= 0 then
		display.pushToast(L("lua_code_text_216"))
		self:onUploadEnd(false, filePath)
	end
end

-- 1.聊天录音成功，上传path获取fileId
-- 2.上传fileId翻译成文本
-- 3.发送消息
function ClassRef:msgUploadAudio(filePath, duration, target)
	if self._audioParam then return end
	self._audioParam = {path=filePath, duration=duration, target=target, audioText=""}
	dump(self._audioParam, "===>IMAPI recordParam")
	self._uploadAudioDict[filePath] = self._audioParam
	self:uploadAudio(filePath)
end

function ClassRef:audio2Text(fileId)
	self:setModeTranslate()
	local code = im.audio2Text(fileId)
	if code ~= 0 then
		display.pushToast(L("lua_code_text_238"))
		self:onAudio2Text(false, fileId)
	end
end

function ClassRef:onAudio2Text(succ, fileId, result)
	if not self._audioParam then return end
	if succ then
		self._audioParam.audioText = result
	end

	app:sendMsg("IMRecordController", "needBackToRealtime")
	app:sendMsg("IMRoomController", "sendAudioMessage", self._audioParam, self._audioParam.target)
	self._audioParam = nil
end
---------------- record audio ----------------

function ClassRef:onDownloadEnd(succ, filePath, fileId)
	local message = self._downloadAudioDict[fileId]
	self._downloadAudioDict[fileId] = nil

	local msgType = type(message)
	if msgType == "table" then
		-- 聊天语言消息
		if succ then
			message:setDownloadState(im.MessageAttachState.Downloaded)
			message:setAudioPath(filePath)
		else
			message:setDownloadState(im.MessageAttachState.Failed)
		end

		-- 组队消息 额外发送消息给TeamModel 用来刷新语音消息
		if message.channelId == "teamreq" then
			app:sendMsg("TeamModel", "onFetchAttachmentComp", message)
		end

		self:dispatchMessageUpdate(message)
		app:sendMsg("IMRoomController", "onFetchAttachmentComp", message)
	elseif msgType == "function" then
		-- 组队语音
		if succ then
			executeFunc(message, fileId, filePath)
		else
			executeFunc(message)
		end
	end

	app:sendMsg("IMRecordController", "needBackToRealtime")
end

-- cb  回调
function ClassRef:downloadAudio(fileId, cb)
	if cb then
		self._downloadAudioDict[fileId] = cb
	end
	self:setModeTranslate()
	local code = im.downloadAudio(fileId, self:getRecordPath())
	-- print("===>IMAPI im.downloadAudio code", code)
	if code ~= 0 then
		self:onDownloadEnd(false, nil, fileId)
	end
end

-- 拉取聊天信息的附件（只有语言）
function ClassRef:fetchAttach(message)
	self._downloadAudioDict[message.fileId] = message
	message:setDownloadState(im.MessageAttachState.Downloading)
	self:downloadAudio(message.fileId)
end

-- 当前选中的频道
function ClassRef:setCurChannelIdx(channelIdx)
	self._curChannelIdx = channelIdx
end

function ClassRef:getCurChannelIdx()
	return self._curChannelIdx
end

-- 当前选择密聊的目标
function ClassRef:setCurP2PTarget(target)
	self._curP2PTarget = target
end

function ClassRef:getCurP2PTarget()
	return self._curP2PTarget
end

function ClassRef:isLastSelectedTarget(target)
	if self._curP2PTarget and self._curP2PTarget.uid == target.uid then
		return true
	end
	return false
end

-- 密聊小红点
function ClassRef:addNewP2PMessage(uid)
	if self._curChannelIdx == 6 and self._curP2PTarget and self._curP2PTarget.uid == uid then
		return
	end
	if self._newP2PMessageList[uid] then
		self._newP2PMessageList[uid] = self._newP2PMessageList[uid] + 1
	else
		self._newP2PMessageList[uid] = 1
		app:sendMsg("IMRoomController", "checkP2PRedPoint", uid)
	end
end

function ClassRef:removeP2PMessage(uid)
	if not self._newP2PMessageList[uid] then
		return
	end
	self._newP2PMessageList[uid] = nil
	app:sendMsg("IMRoomController", "checkP2PRedPoint", uid)
end

-- 目标新消息条数
function ClassRef:getNewMessageNumFormId(uid)
	if self._newP2PMessageList[uid] then
		return self._newP2PMessageList[uid]
	end
	return 0
end

function ClassRef:isShowP2PRedPoint()
	if table.nums(self._newP2PMessageList) > 0 then
		return true
	end
	return false
end

function ClassRef:getChannelIdBySettingIdx(idx)
	return SETTINGIDX_CHANNELID[idx]
end

function ClassRef:getSettingIdxByChannelName(channelId)
	for i, v in ipairs(SETTINGIDX_CHANNELID) do
		if v == channelId then
			return i
		end
	end
end

function ClassRef:SettingImChannelInfo(idx, b)
	local channelId = self:getChannelIdBySettingIdx(idx)
	if not channelId or #self._allMsgList == 0 then return end
	for i, v in ipairs(self._allMsgList) do
		if v.channelId == channelId then
			v.showFlag = b
		end
	end
	if self._curChannelIdx == 1 then -- 当前是综合频道立即刷新聊天界面
		EM:notify("refreshIMAllChannel")
	end
end

-- 清除某位玩家的发言
function ClassRef:onClearMessage(uid)
	local function removeTable(oriTable)
		local newTable = {}
		local isremove = false
		for k, v in ipairs(oriTable) do
			local sender = v.from
			if sender ~= uid then
				table.insert(newTable, v)
			else
				isremove = true
			end
		end
		return newTable, isremove
	end
	local flag = false -- 表示有删除的元素需要刷新
	local newMsgDict = {}
	local newMyMsgDict = {}
	-- all
	self._allMsgList, flag = removeTable(self._allMsgList)

	-- world
	for k, channelInfo in pairs(self._msgDict) do
		newMsgDict[k], flag = removeTable(channelInfo)
	end
	self._msgDict = newMsgDict

	--p2p
	for k, p2pInfo in pairs(self._myMsgDict) do
		newMyMsgDict[k], flag = removeTable(p2pInfo)
	end
	self._myMsgDict = newMyMsgDict

	-- team
	self._teamMsgList, flag = removeTable(self._teamMsgList)

	if flag then
		EM:notify("refreshIMAllChannel")
	end
end

return ClassRef
